﻿//----------------------------------------------------------------------------------------------------
// The LevelManager is responsible for laoding and displaying levels
//----------------------------------------------------------------------------------------------------

package HG.Managers
{
	import flash.utils.ByteArray;
	import flash.geom.Point;
	
	import HG.GameService;
	import HG.Managers.PlayerManager;
	
	import HG.GameDataTypes.Level;
	import HG.GameDataTypes.NodeInstance;
	
	import HG.TypeInterfaces.LevelFileInterface;
	
	import HG.Debug;
	
	import HG.Visual.VisualLevel;
	import HG.Visual.VisualNode;
	import HG.Visual.VisualConnection;
	
	import HG.Events.LevelEvent;
	import HG.Events.NodeEvent;
	import HG.Visual.VisualAttachPoint;
	
	
	public class LevelManager extends IGameManager
	{
		var m_currentLevel:Level;
		var m_visualLevel:VisualLevel;
		
		var m_playerManager:PlayerManager;
		
		var m_nEvt:NodeEvent;
		var m_lEvt:LevelEvent;
		
		var m_editorMode:Boolean;
		
		//----------------------------------------------------------------------------------------------------
		public function LevelManager()
		{
			m_editorMode = false;
		}
			
		//----------------------------------------------------------------------------------------------------
		override public function Initialize()
		{
			m_playerManager = GameService.GetInstance().GetPlayerManager();
		}
		
		//----------------------------------------------------------------------------------------------------
		override public function Shutdown()
		{
			
		}
		
		//----------------------------------------------------------------------------------------------------
		override public function OnTick(DeltaTime:Number)
		{
			
		}
		
		//----------------------------------------------------------------------------------------------------
		public function SetEditorMode(editor:Boolean)
		{
			m_editorMode = editor;
		}
		
		//----------------------------------------------------------------------------------------------------
		public function GetEditorMode():Boolean
		{
			return m_editorMode;
		}
		
		//----------------------------------------------------------------------------------------------------
		// Event callbacks
		//----------------------------------------------------------------------------------------------------
		public function RaiseLevelLoadedEvent()
		{
			m_lEvt = new LevelEvent(LevelEvent.LOAD);
			dispatchEvent(m_lEvt);
		}
		
		//----------------------------------------------------------------------------------------------------
		public function RaiseLevelUnLoadedEvent()
		{
			m_lEvt = new LevelEvent(LevelEvent.UNLOAD);
			dispatchEvent(m_lEvt);
		}
		
		//----------------------------------------------------------------------------------------------------
		public function RaiseNodeCapturedEvent(visNode:VisualNode, playerID:Number)
		{
			m_nEvt = new NodeEvent(NodeEvent.CAPTURE);
			m_nEvt.m_node = visNode;
			m_nEvt.m_capBy = playerID;
			dispatchEvent(m_nEvt)
		}
		
		//----------------------------------------------------------------------------------------------------
		public function RaiseNodeSpawnedEvent(visNode:VisualNode)
		{
			m_nEvt = new NodeEvent(NodeEvent.SPAWN);
			m_nEvt.m_node = visNode;
			dispatchEvent(m_nEvt);
		}
		
		//----------------------------------------------------------------------------------------------------
		// Internal functions
		//----------------------------------------------------------------------------------------------------
		public function CreateLevel():Level
		{
			m_currentLevel = new Level();
			
			RaiseLevelLoadedEvent();
			
			return GetCurrentLevel();
		}
		
		//----------------------------------------------------------------------------------------------------
		public function LoadLevel(levelID:Number)
		{
			UnloadLevel()
			
			var file:LevelFileInterface = new LevelFileInterface("Levels\\" + levelID);
			file.LoadLevel(LevelLoaded);
		}
		
		//----------------------------------------------------------------------------------------------------
		private function UnloadLevel()
		{
			// Unload
			m_visualLevel.ClearAll();
			m_visualLevel.visible = true;
			RaiseLevelUnLoadedEvent();
		}
		
		//----------------------------------------------------------------------------------------------------
		private function LevelLoaded(level:Level)
		{
			Debug.ASSERT(level, "Loaded level does not exist!");
			
			m_currentLevel = level;
			
			m_visualLevel.SetName(level.GetName());
			m_visualLevel.SetGameType(level.GetGameType());
			
			var nodes:Array = level.GetNodes();
			
			var index:Number = 0;
			var listLength:Number = nodes.length;
			
			for (index = 0; index < listLength; ++index)
			{
				var node:NodeInstance = nodes[index];
				
				Debug.ASSERT(node, "Invalid node loaded!");
				
				var visualNode:VisualNode = m_visualLevel.AddVisualNode(node.GetType(), node.GetID());
				
				visualNode.SetSource(m_visualLevel.GetVisualAttachPoint(node.GetAttachID()), false);
				
				visualNode.SetTripChances(node.GetTripChances());
				visualNode.SetEncryptionKey(node.GetEncryptionKey());
				visualNode.SetVisibleDelay(true, (Math.random() * 1024));
				
				// Give all root nodes to the player.
				if (node.GetType() == NodeManager.NODE_ROOT)
				{
					visualNode.AddOcupant(m_playerManager.AddPlayer(PlayerManager.PLAYER_HUMAN, visualNode.GetID()));
				}
				
				if (node.GetType() == NodeManager.NODE_SENTRY)
				{
					visualNode.AddOcupant(m_playerManager.AddPlayer(PlayerManager.PLAYER_COMPUTER, visualNode.GetID()));
				}
				
				// Events
				RaiseNodeSpawnedEvent(visualNode);
			}
			
			for (index = 0; index < listLength; ++index)
			{
				Debug.ASSERT(nodes[index], "Invalid node loaded for connection!");
				
				var rootID:Number = nodes[index].GetID();
				var conArray:Array = nodes[index].GetConnections();
				
				var conIndex:Number = 0;
				var conListLength:Number = conArray.length;
				
				for (conIndex = 0; conIndex < conListLength; ++conIndex)
				{
					var visualConnection:VisualConnection = m_visualLevel.AddVisualConnectionEx(rootID, conArray[conIndex]);
					
					if (visualConnection)
					{
						visualConnection.SetVisibleDelay(true, (Math.random() * 1024));
					}
				}
			}
			
			RaiseLevelLoadedEvent();
		}

		//----------------------------------------------------------------------------------------------------
		public function SaveCurrentLevel()
		{
			var file:LevelFileInterface = new LevelFileInterface(m_currentLevel.GetName());
			file.SaveLevel(m_currentLevel);
		}
		
		//----------------------------------------------------------------------------------------------------
		public function GetCurrentLevel():Level
		{
			return m_currentLevel;
		}
		
		//----------------------------------------------------------------------------------------------------
		public function SetVisualLevelContainer(visLevel:VisualLevel)
		{
			m_visualLevel = visLevel;
		}
		
		//----------------------------------------------------------------------------------------------------
		public function GetVisualNode(nodeID:Number):VisualNode
		{
			return m_visualLevel.GetVisualNode(nodeID);
		}
		
		//----------------------------------------------------------------------------------------------------
		public function GetVisualNodes():Array
		{
			return m_visualLevel.GetVisualNodes();
		}
		
		//----------------------------------------------------------------------------------------------------
		public function GetVisualNodesOcupiedByPlayer(playerID:Number):Array
		{
			return m_visualLevel.GetVisualNodesOcupiedByPlayer(playerID);
		}
		
		//----------------------------------------------------------------------------------------------------
		public function GetVisualConnection(fromID:Number, toID:Number):VisualConnection
		{
			return m_visualLevel.GetVisualConnection(fromID, toID);
		}
		
		//----------------------------------------------------------------------------------------------------
		public function GetVisualConnectionsTo(toID:Number):Array
		{
			return m_visualLevel.GetVisualConnectionsTo(toID);
		}
		
		//----------------------------------------------------------------------------------------------------
		public function GetAvailableVisualConnectionsTo(playerID:Number, toID:Number):Array
		{
			return m_visualLevel.GetAvailableVisualConnectionsTo(playerID, toID);
		}
		
		//----------------------------------------------------------------------------------------------------
		public function GetVisualConnections():Array
		{
			return m_visualLevel.GetVisualConnections();
		}
		
		//----------------------------------------------------------------------------------------------------
		public function GetPathBetween(fromNodeID:Number, toNodeID:Number):Array
		{
			return m_visualLevel.GetPathBetween(fromNodeID, toNodeID);
		}
		
		//----------------------------------------------------------------------------------------------------
		// Imports the data from a visual level and pushes it to a level object.
		// - Used for the editor, which works backwards comapred to the game.
		//----------------------------------------------------------------------------------------------------
		public function SetLevelDataFromVisual()
		{
			Debug.ASSERT(m_visualLevel, "No Visual Level attached to save");
			
			var m_visualNodes:Array = m_visualLevel.GetVisualNodes();
			
			var index:Number = 0;
			var listLength:Number = m_visualNodes.length;
			
			m_currentLevel = new Level();
			
			m_currentLevel.SetName(m_visualLevel.GetName());
			m_currentLevel.SetGameType(m_visualLevel.GetGameType());
			
			// Get sentry nodes.
			var sentryNodes:Array = new Array();
			for (index = 0; index < listLength; ++index)
			{
				var sentryNode:VisualNode = m_visualNodes[index];
				
				if (sentryNode.GetType() == NodeManager.NODE_SENTRY)
					sentryNodes.push(sentryNode.GetID());
			}
			
			for (index = 0; index < listLength; ++index)
			{
				var node:VisualNode = m_visualNodes[index];
				
				Debug.ASSERT(node, "Null Node");
				
				var nodeInstance:NodeInstance = new NodeInstance();
				nodeInstance.SetID(node.GetID());
				
				// Work out senry trip values here.
				if (sentryNodes.length > 0)
				{
					var index2:Number = 0;
					var listLength2:Number = sentryNodes.length;
					
					for (index2 = 0; index2 < listLength2; ++index2)
					{
						var dist:Number = m_visualLevel.GetDistanceBetween(sentryNodes[index2], node.GetID());
						
						if (dist <= 0)
							continue;
						
						var sentryRange:Number = 5;
						
						var percentile = (sentryRange - dist) / sentryRange;
						if (percentile < 0)
							percentile = 0;
						
						nodeInstance.AddTripChance(percentile, sentryNodes[index2]);
					}
				}
			
				nodeInstance.SetType(node.GetType());
				nodeInstance.SetConnections(node.GetConnections());
				nodeInstance.SetEncryptionKey(node.GetEncryptionKey());
				nodeInstance.SetAttachID(node.GetSource().GetID());
				
				m_currentLevel.AddNode(nodeInstance);
			}
		}
		
		//----------------------------------------------------------------------------------------------------
	}
}